﻿//#define CONTRACTS_FULL

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace BoatNGoat.Logic.Map.Generator
{
    [ContractClass(typeof(HeightFunctionContract))] // This is kind of cool, but it only works if you install the code contracts addon
    interface IHeightFunction
    {
        /// <summary>
        /// Get a height between -1.0 and 1.0 from an x,y position
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns>Height between -1.0 and 1.0</returns>
        double Z(int x, int y);

    }

    class RegularBumpsGenerator : IHeightFunction
    {
        public double Z(int x, int y)
        {
            return 0.5*(Math.Sin(0.5*x) + Math.Sin(0.5*y));
        }
    }

    class CompositionFunction : IHeightFunction
    {
        private readonly List<IHeightFunction> _functions;
        private readonly Func<List<double>, double> _composer;

        public CompositionFunction(List<IHeightFunction> functions, Func<List<double>, double> compositionRule)
        {
            _functions = functions;
            _composer = compositionRule;
        }

        public double Z(int x, int y)
        {
            List<double> results = _functions.Select(f => f.Z(x,y)).ToList();
            return _composer(results);
        }
    }

    // Make sure people are following the -1<=z<=1 rule
    [ContractClassFor(typeof(IHeightFunction))]
    internal abstract class HeightFunctionContract : IHeightFunction
    {
        public double Z(int x, int y)
        {
            // If you're here then you've returned the wrong height
            Contract.Ensures(Contract.Result<double>() >= -1.0);
            Contract.Ensures(Contract.Result<double>() <= 1.0);
            return default(double);
        }
    }
}
